package com.xiaolin.designmode.prototype;

/**
 * @ClassName DeepClone
 * @Description 原型模式
 * @Detail     原型模式-深克隆，要求原型类的引用类型的属性都要实现Cloneable接口，重写clone()方法，
 *              如果只有原型类实现Cloneable方法，那么只有原型类是深克隆，其引用类型的属性都是浅克隆
 *              步骤：
 *                  1、创建一个原型类
 *                  2、实现Cloneable接口
 *                  3、重写克隆方法
 *                  4、测试
 *              总结：
 *                  1、用一个已经创建的实例作为原型，通过复制该原型对象来创建一个和原型相同或相似的新对象
 *                  2、角色
 *                      1、原型类(也可以是一个原型抽象类（接口），具体原型类去实现该抽象类（接口）)
 *                          重写克隆方法
 *                      2、客户端
 *                  3、适用场景
 *                      1、创建对象成本较大，例如初始化时间长，占用CPU太多，或者占用网络资源太多等，需要优化资源。
 *                      2、创建一个对象需要繁琐的数据准备或访问权限等，需要提高性能或者提高安全性。
 *                      3、系统中大量使用该类对象，且各个调用者都需要给它的属性重新赋值。
 *                      4、对象之间相同或相似，即只是个别的几个属性不同的时候。
 * @Author MyPC
 * @Date 2020/10/27
 * @Version 1.0
 */
public class DeepClone implements Cloneable{
    //基本类型
    private Integer age;
    //字符串类型
    private String name;
    //普通对象类型
    private Person person;

    public DeepClone(){
        System.out.println("原型对象创建成功");
    }

    /**
     * 重写克隆方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("复制原型对象");
        DeepClone deepClone = (DeepClone) super.clone();
        //深克隆
        deepClone.person= (Person) person.clone();
        return deepClone;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        //创建原型类
        DeepClone p = new DeepClone();
        p.name="小林";
        p.age=18;
        Person person=new Person();
        person.setSex("男");
        p.person=person;
        //克隆原型类
        DeepClone clone = (DeepClone) p.clone();
        System.out.println(p==clone);
        //由于是深克隆，这两个引用的地址不同
        System.out.println(p.person==clone.person);
        System.out.println(clone.name);
        System.out.println(clone.person.getSex());
    }
}

/**
 * 该类实现了Cloneable接口，可以实现深克隆
 */
class Person implements Cloneable{
    private String sex;

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getSex() {
        return sex;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return (Person)super.clone();
    }
}
